<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  
    
      
    

    
  

  

  
    
      
    

    
  

  
    
      
    

    
  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Monda:300,300italic,400,400italic,700,700italic|Roboto Slab:300,300italic,400,400italic,700,700italic|PT Mono:300,300italic,400,400italic,700,700italic|PT Mono:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Three.js," />










<meta name="description" content="前言前段时间将《Three.js入门指南》匆匆的翻了一翻，算是对Three.js有了一个较为基本的印象，但脑海中对其中的一些概念还是没有什么理解，因此决定对这些知识都进行一个较为深入的理解与学习。首先便从几何体的基本构成开始吧。下面就是关于几何体对象的思维导图（如有错误敬请指正！）：  一、几何体对象概述在Three.js中，我们如果可以通过各式各样的API来构建一个几何体，下面是部分构建几何体的">
<meta name="keywords" content="Three.js">
<meta property="og:type" content="article">
<meta property="og:title" content="Three.js几何体的那些事儿">
<meta property="og:url" content="http://srtian96.gitee.io/blog/2019/01/15/Three.js几何体的那些事儿/index.html">
<meta property="og:site_name" content="Srtian&#39;Blog">
<meta property="og:description" content="前言前段时间将《Three.js入门指南》匆匆的翻了一翻，算是对Three.js有了一个较为基本的印象，但脑海中对其中的一些概念还是没有什么理解，因此决定对这些知识都进行一个较为深入的理解与学习。首先便从几何体的基本构成开始吧。下面就是关于几何体对象的思维导图（如有错误敬请指正！）：  一、几何体对象概述在Three.js中，我们如果可以通过各式各样的API来构建一个几何体，下面是部分构建几何体的">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://images.gitee.com/uploads/images/2019/0115/202632_47506164_1575229.png">
<meta property="og:updated_time" content="2019-01-15T13:00:06.981Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Three.js几何体的那些事儿">
<meta name="twitter:description" content="前言前段时间将《Three.js入门指南》匆匆的翻了一翻，算是对Three.js有了一个较为基本的印象，但脑海中对其中的一些概念还是没有什么理解，因此决定对这些知识都进行一个较为深入的理解与学习。首先便从几何体的基本构成开始吧。下面就是关于几何体对象的思维导图（如有错误敬请指正！）：  一、几何体对象概述在Three.js中，我们如果可以通过各式各样的API来构建一个几何体，下面是部分构建几何体的">
<meta name="twitter:image" content="https://images.gitee.com/uploads/images/2019/0115/202632_47506164_1575229.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Gemini',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://srtian96.gitee.io/blog/2019/01/15/Three.js几何体的那些事儿/"/>





  <title>Three.js几何体的那些事儿 | Srtian'Blog</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Srtian'Blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">It's better to burn out than to fade away</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/blog/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/blog/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/blog/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocomplete="off"
             placeholder="搜索..." spellcheck="false"
             type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://srtian96.gitee.io/blog/blog/2019/01/15/Three.js几何体的那些事儿/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Srtian">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Srtian'Blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Three.js几何体的那些事儿</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-01-15T20:57:06+08:00">
                2019-01-15
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/Three-js/" itemprop="url" rel="index">
                    <span itemprop="name">Three.js</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          
            <span class="post-meta-divider">|</span>
            <span class="page-pv">本文总阅读量
            <span class="busuanzi-value" id="busuanzi_value_page_pv" ></span>次
            </span>
          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  1,702
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长">
                  7
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>前段时间将《Three.js入门指南》匆匆的翻了一翻，算是对Three.js有了一个较为基本的印象，但脑海中对其中的一些概念还是没有什么理解，因此决定对这些知识都进行一个较为深入的理解与学习。首先便从几何体的基本构成开始吧。<br>下面就是关于几何体对象的思维导图（如有错误敬请指正！）：</p>
<p><img src="https://images.gitee.com/uploads/images/2019/0115/202632_47506164_1575229.png" alt="输入图片说明" title="几何体对象.png"></p>
<h3 id="一、几何体对象概述"><a href="#一、几何体对象概述" class="headerlink" title="一、几何体对象概述"></a>一、几何体对象概述</h3><p>在Three.js中，我们如果可以通过各式各样的API来构建一个几何体，下面是部分构建几何体的API，我们可以通过官方文档来进行查阅：</p>
<blockquote>
<p><a href="https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene" target="_blank" rel="noopener">https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene</a></p>
<ul>
<li>BoxBufferGeometry</li>
<li>BoxGeometry</li>
<li>CircleBufferGeometry</li>
<li>CircleGeometry</li>
<li>ConeBufferGeometry</li>
<li>ConeGeometry</li>
<li>CylinderBufferGeometry</li>
<li>CylinderGeometry</li>
<li>…</li>
</ul>
</blockquote>
<p>很明显，如果使用There.js所提供的API构建集合体是非常方便的，比如这样：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> geometry = <span class="keyword">new</span> THREE.BoxGeometry(<span class="number">100</span>, <span class="number">100</span>, <span class="number">100</span>);</span><br></pre></td></tr></table></figure>
<p>上面的代码就可以让我们生成一个长、宽、高都为100的长方体，我们在后面所需做的就是将材质、灯光等属性设置完毕即可。这虽然简单便捷，但本质上就是一个黑盒，我们如果不加以深究，就只能在Three.js所封装好的API的基础进行开发，一旦有Three.js所提供的API所不能完成的需求出现时，就很可能无能为力。此外，如果对这些几何体的构成如果进行一些了解，也能有助于我们理解其几何体的本质。</p>
<p>通过上面那些封装好的对象的名字我们不难发现，大致的几何体类型有两大类：</p>
<ol>
<li>BufferGeometry</li>
<li>Geometry</li>
</ol>
<p>这两者的区别就在于 BufferGeometry 顶点数据是使用类型化数组来表示的，而Geometry的顶点数据则是用对象来表示的。</p>
<h3 id="二、BufferGeometry"><a href="#二、BufferGeometry" class="headerlink" title="二、BufferGeometry"></a>二、BufferGeometry</h3><p>当我们使用 BufferGeometry 时，我们可以这么来声明几何体顶点数据：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> geometry = <span class="keyword">new</span> THREE.BufferGeometry()</span><br><span class="line"><span class="comment">// 使用类型数组来创建顶点数据</span></span><br><span class="line"><span class="keyword">const</span> vertices = <span class="keyword">new</span> <span class="built_in">Float32Array</span>([</span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="comment">// 顶点1的坐标，下面分别是顶点2,3,4,5,6的坐标</span></span><br><span class="line">  <span class="number">100</span>, <span class="number">0</span>, <span class="number">0</span>, </span><br><span class="line">  <span class="number">0</span>, <span class="number">100</span>, <span class="number">0</span>, </span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">100</span>, </span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">100</span>, </span><br><span class="line">  <span class="number">100</span>, <span class="number">0</span>, <span class="number">10</span>, </span><br><span class="line">])</span><br><span class="line"><span class="comment">// 创建属性缓冲区对象，每3个为一组，分别表示一个顶点的xyz坐标</span></span><br><span class="line"><span class="keyword">const</span> attribue = <span class="keyword">new</span> THREE.BufferAttribute(vertices, <span class="number">3</span>)</span><br><span class="line"><span class="comment">// 设置几何体attributes属性的位置属性</span></span><br><span class="line">geometry.attributes.position = attribue</span><br></pre></td></tr></table></figure></p>
<p>通过上面的代码我们就能够声明几何体对象顶点的位置属性了，同样的我们也能设置颜色属性：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> colors = <span class="keyword">new</span> <span class="built_in">Float32Array</span>([</span><br><span class="line">  <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>,</span><br><span class="line">  <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>,</span><br><span class="line">  <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>,</span><br><span class="line">  <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>,</span><br><span class="line">])</span><br><span class="line"><span class="comment">// 设置几何体attributes属性的颜色color属性，三个为一组</span></span><br><span class="line">geometry.attributes.color = <span class="keyword">new</span> THREE.BufferAttribute(colors, <span class="number">3</span>)</span><br></pre></td></tr></table></figure>
<p>同样的法向量也是如此：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> normals = <span class="keyword">new</span> <span class="built_in">Float32Array</span>([</span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>,</span><br><span class="line">  <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>,</span><br><span class="line">])</span><br><span class="line"><span class="comment">// 设置几何体attributes属性的位置normal属性。三个为一组</span></span><br><span class="line">geometry.attributes.normal = <span class="keyword">new</span> THREE.BufferAttribute(normals, <span class="number">3</span>)</span><br></pre></td></tr></table></figure>
<p>通过上面的示例我们不难看出，当我们使用BufferGeometry来声明一个几何体对象时，我们可以通过一个个类型化的数据来声明顶点的具体情况，具体情况可参阅官方文档：</p>
<blockquote>
<p><a href="https://threejs.org/docs/index.html#api/en/core/BufferGeometry" target="_blank" rel="noopener">https://threejs.org/docs/index.html#api/en/core/BufferGeometry</a></p>
</blockquote>
<p>当然，这种申明方式既有优点又有缺点，优点就是实现了高度的可定制化，可以手动的设置每个顶点的属性，而缺点就在于一是手动设置麻烦，而是如果顶点过多，每个顶点都进行渲染的话会造成性能上的浪费，毕竟在绘制大的图形时，必定会有不少的顶点是重合的。为了减少这些缺点给项目带来的负面影响，Three.js又为我们提供了indedx。下面是官方文档对于index的描述：</p>
<blockquote>
<p>.index : （BufferAttribute）<br>Allows for vertices to be re-used across multiple triangles; this is called using “indexed triangles” and works much the same as it does in Geometry: each triangle is associated with the indices of three vertices. This attribute therefore stores the index of each vertex for each triangular face. If this attribute is not set, the renderer assumes that each three contiguous positions represent a single triangle. Default is null.</p>
</blockquote>
<p>具体的使用情况如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> indexes = <span class="keyword">new</span> <span class="built_in">Uint16Array</span>([</span><br><span class="line">  <span class="number">0</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>,</span><br><span class="line">])</span><br><span class="line"><span class="comment">// 设置为一个为一组，则0代表上面属性的第一组</span></span><br><span class="line">geometry.index = <span class="keyword">new</span> THREE.BufferAttribute(indexes, <span class="number">1</span>)</span><br></pre></td></tr></table></figure>
<h3 id="三、Geometry"><a href="#三、Geometry" class="headerlink" title="三、Geometry"></a>三、Geometry</h3><p>与BufferGeometry不同的是，Geometry是使用对象来描述顶点数据的就像这样：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> geometry = <span class="keyword">new</span> THREE.Geometry()</span><br><span class="line"><span class="comment">// 使用Vector3向量对象来表示顶点位置数据</span></span><br><span class="line"><span class="keyword">const</span> p1 = <span class="keyword">new</span> THREE.Vector3(<span class="number">50</span>, <span class="number">60</span>, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">const</span> p2 = <span class="keyword">new</span> THREE.Vector3(<span class="number">0</span>, <span class="number">70</span>, <span class="number">20</span>)</span><br><span class="line"><span class="keyword">const</span> p3 = <span class="keyword">new</span> THREE.Vector3(<span class="number">80</span>, <span class="number">70</span>, <span class="number">0</span>)</span><br><span class="line"><span class="comment">// vertices是一个数组，因此我们只需将顶点push进去即可</span></span><br><span class="line">geometry.vertices.push(p1, p2, p3)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用Color对象来表示顶点颜色数据</span></span><br><span class="line"><span class="keyword">const</span> color1 = <span class="keyword">new</span> THREE.Color(<span class="number">0x00ff00</span>)</span><br><span class="line"><span class="keyword">const</span> color2 = <span class="keyword">new</span> THREE.Color(<span class="number">0x0000ff</span>)</span><br><span class="line"><span class="keyword">const</span> color3 = <span class="keyword">new</span> THREE.Color(<span class="number">0xff0000</span>)</span><br><span class="line"><span class="comment">// 将顶点颜色数据添加到geometry对象</span></span><br><span class="line">geometry.colors.push(color1, color2, color3)</span><br></pre></td></tr></table></figure></p>
<p>这样是不是很简单呀，但需要注意的是，在Geometry这个积类中，顶点的颜色颜色属性只能作用于点材质与线材质的几何体，对mesh类型的几何体没有作用。因此当我们需要使用mesh类型的几何体时，我们就需要使用face3属性来帮我们实现颜色上的定义，此外face3的用法与BufferGeometry中的index也很相像，都运用了顶点复用的思想：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> geometry = <span class="keyword">new</span> THREE.Geometry()</span><br><span class="line"><span class="comment">// 使用Vector3向量对象来表示顶点位置数据</span></span><br><span class="line"><span class="keyword">const</span> p1 = <span class="keyword">new</span> THREE.Vector3(<span class="number">50</span>, <span class="number">60</span>, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">const</span> p2 = <span class="keyword">new</span> THREE.Vector3(<span class="number">0</span>, <span class="number">70</span>, <span class="number">20</span>)</span><br><span class="line"><span class="keyword">const</span> p3 = <span class="keyword">new</span> THREE.Vector3(<span class="number">80</span>, <span class="number">70</span>, <span class="number">0</span>)</span><br><span class="line"><span class="comment">// vertices是一个数组，因此我们只需将顶点push进去即可</span></span><br><span class="line">geometry.vertices.push(p1, p2, p3)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用Color对象来表示顶点颜色数据</span></span><br><span class="line"><span class="keyword">const</span> color1 = <span class="keyword">new</span> THREE.Color(<span class="number">0x00ff00</span>)</span><br><span class="line"><span class="keyword">const</span> color2 = <span class="keyword">new</span> THREE.Color(<span class="number">0x0000ff</span>)</span><br><span class="line"><span class="keyword">const</span> color3 = <span class="keyword">new</span> THREE.Color(<span class="number">0xff0000</span>)</span><br><span class="line"><span class="comment">// 将顶点颜色数据添加到geometry对象</span></span><br><span class="line">geometry.colors.push(color1, color2, color3)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用Face3构造函数创建一个三角面</span></span><br><span class="line"><span class="keyword">const</span> face1 = <span class="keyword">new</span> THREE.Face3(<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line"><span class="comment">//设置每个顶点的法向量</span></span><br><span class="line"><span class="keyword">const</span> n1 = <span class="keyword">new</span> THREE.Vector3(<span class="number">0</span>, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"><span class="keyword">const</span> n2 = <span class="keyword">new</span> THREE.Vector3(<span class="number">0</span>, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"><span class="keyword">const</span> n3 = <span class="keyword">new</span> THREE.Vector3(<span class="number">0</span>, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"><span class="comment">// 等于这样的：face1.normal = new THREE.Vector3(0, 0, -1)</span></span><br><span class="line">face1.vertexNormals.push(n1, n2, n3);</span><br><span class="line"><span class="comment">// 设置三角面face1三个顶点的颜色</span></span><br><span class="line">face1.vertexColors = [</span><br><span class="line">  <span class="keyword">new</span> THREE.Color(<span class="number">0xffff00</span>),</span><br><span class="line">  <span class="keyword">new</span> THREE.Color(<span class="number">0xff00ff</span>),</span><br><span class="line">  <span class="keyword">new</span> THREE.Color(<span class="number">0x00ffff</span>),</span><br><span class="line">]</span><br><span class="line"><span class="comment">// 若颜色一样只需这么声明：face1.color = new THREE.Color(0x00ff00);</span></span><br><span class="line"></span><br><span class="line">geometry.faces.push(face1)</span><br></pre></td></tr></table></figure>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/blog/tags/Three-js/" rel="tag"># Three.js</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/12/29/《点石成金》读书笔记/" rel="next" title="《点石成金》">
                <i class="fa fa-chevron-left"></i> 《点石成金》
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2019/02/13/Web语义化的那些事儿/" rel="prev" title="Web语义化的那些事儿">
                Web语义化的那些事儿 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/blog/images/avatar.jpg"
                alt="Srtian" />
            
              <p class="site-author-name" itemprop="name">Srtian</p>
              <p class="site-description motion-element" itemprop="description">JUST DO IT.</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">59</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/blog/categories/index.html">
                  <span class="site-state-item-count">15</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/blog/tags/index.html">
                  <span class="site-state-item-count">37</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          

          
            <div class="links-of-author motion-element">
                
                  <span class="links-of-author-item">
                    <a href="https://gitee.com/srtian96" target="_blank" title="GitHub">
                      
                        <i class="fa fa-fw fa-github"></i>GitHub</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="shenruotian@gmail.com" target="_blank" title="E-Mail">
                      
                        <i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                  </span>
                
            </div>
          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#一、几何体对象概述"><span class="nav-number">2.</span> <span class="nav-text">一、几何体对象概述</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#二、BufferGeometry"><span class="nav-number">3.</span> <span class="nav-text">二、BufferGeometry</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#三、Geometry"><span class="nav-number">4.</span> <span class="nav-text">三、Geometry</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Srtian</span>
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js">
</script>
  
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
    
      <span class="post-meta-item-text">Site words total count&#58;</span>
    
    <span title="Site words total count">102.8k</span>
  
</div>





        
<div class="busuanzi-count">
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      本站访客数
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      人次
    </span>
  

  
    <span class="site-pv">
      本站总访问量
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      次
    </span>
  
</div>








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  

  <script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/blog/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url);
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script>





  

  

  

  
  

  

  

  

</body>
</html>
